﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ActionSystem.Core.Utils;
namespace ActionSystem.Core.EventSystem
{
    /// <summary>
    /// 事件系统基类
    /// 存在事件优先级，可以阻止事件传递
    /// </summary>
    /// <typeparam name="N">事件系统类型</typeparam>
    public class EventSystem
    {
        Dictionary<int, List<IEvent>> events = new Dictionary<int, List<IEvent>>();
        SystemState state;
        enum SystemState
        {
            Free = 0,
            OnEvent = 1
        }
        public EventSystem()
        {
            events.Clear();
            state = SystemState.Free;
        }

        /// <summary>
        /// 注册事件
        /// </summary>
        /// <param name="handler"></param>
        public void RegisterListener(int eventId,IEvent handler)
        {
            //正在执行
            if (state == SystemState.OnEvent)
            {
                throw new System.Exception("不能在输入系统分发事件时调用注册");

            }
            if(!events.ContainsKey(eventId))
            {
                events.Add(eventId,new List<IEvent>());
            }
            var handlers = events[eventId];
            //加入
            if (!handlers.Contains(handler))
            {
                handlers.Add(handler);
            }
            //排序,从大到小
            handlers.Sort((a, b) =>
            {
                return -(a.Priority > b.Priority ? 1 : a.Priority == b.Priority ? 0 : -1);
            });
        }

        public void ResetSystem()
        {
            while (caches.Count > 0)
            {
                var cache = caches.Dequeue();
                var arg = cache.arg;
                (arg as IPoolItem)?.PoolItemDelete();
                cache.PoolItemDelete();
            }
            events.Clear();
        }

        /// <summary>
        /// 取消注册
        /// </summary>
        /// <param name="handler"></param>
        public void UnRegisterListenser(int eventId,IEvent handler)
        {
            //正在执行
            if (state == SystemState.OnEvent)
            {
                throw new System.Exception("不能在输入系统分发事件时调用注销");
            }
            if (!events.ContainsKey(eventId))
            {
                return;
            }
            var handlers = events[eventId];
            //删除
            if (handlers.Contains(handler))
            {
                handlers.Remove(handler);
                if(handlers.Count==0)
                {
                    events.Remove(eventId);
                }
            }
        }

        Queue<EventCache> caches=new Queue<EventCache>();
        public void Invoke()
        {            
            state = SystemState.OnEvent;
            while(caches.Count>0)
            {
                var cache = caches.Dequeue();
                int eventId = cache.id;
                var arg = cache.arg;
                if (events.ContainsKey(eventId))
                {
                    var handlers = events[eventId];
                    for (int i = 0; i < handlers.Count; i++)
                    {
                        if (handlers[i].OnEvent(eventId,arg))
                        {
                            break;
                        }
                    }
                }
                (arg as IPoolItem)?.PoolItemDelete();
                cache.PoolItemDelete();
            }
            
            state = SystemState.Free;
        }

        /// <summary>
        /// 抛出事件
        /// </summary>
        /// <param name="data"></param>
        public void RaiseEvent(int eventId,EventArg data)
        {
            var c = GeneticPool<EventCache>.Create();
            c.id = eventId;
            c.arg = data;
            caches.Enqueue(c);
        }
        class EventCache:IPoolItem
        {
            public int id;
            public EventArg arg;
            public bool IsDeleted { get ; set; }

            public void PoolItemReset()
            {
                id = 0;
                arg = null;
            }

            public void PoolItemDelete()
            {
                GeneticPool<EventCache>.Delete(this);
            }
        }
    }
}

